home *** CD-ROM | disk | FTP | other *** search
- #include "matrix.hxx"
- #include <math.h>
- #include <ctype.h>
- #include <time.h>
- #ifndef DOS
- #include <sys/param.h>
- #endif
- #define UPCASE(X) (X = islower(X) ? toupper(X) : X) /* force a char to upper case */
-
- /*
- -*++ matrix::matrix(): contructs a matrix of any size and inits to 0
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix::matrix(int rows = 1 , int cols = 1, double initval = 0)
- {
- p = new matrep;
- p->m_vec = new _Vector*[rows];
- p->m_rows = rows;
- p->m_cols = cols;
- for (int i = 0; i < rows; i++)
- p->m_vec[i] = new _Vector(cols);
- for (i=0; i < rows; i++)
- for (int j = 0; j < cols; j++)
- (*this)[i][j] = initval;
- p->n = 1; /* so far, only one reference to this data */
- }
-
-
- /*
- -*++ matrix::matrix(): adds a new reference to an existing matrix
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: "Reference counting" is a method of managing garbage.
- ** Instead of creating a whole new object every time you use (for instance) an
- ** equal sign, it makes more sense just to point at the old object. This
- ** means you can have several objects all pointing at the same thing. When
- ** you start destroying objects, you don't want to destroy the original thing
- ** until you only have one reference left.
- ** ++*)
- */
-
- matrix::matrix(matrix& x)
- {
- x.p->n++; /* we're adding another reference, so increase */
- p = x.p; /* the count. */
- }
-
-
- /*
- -*++ ch_find(): search an input stream for a char, ignoring comments
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: searches an input stream for c, ignoring comments starting
- ** with '#' to end of line. Errfunc is the address of an error function,
- ** fname is the name of the source file.
- ** ++*)
- */
-
- void ch_find(istream& from, char ch, void (*errfunc)(char *), char * fname)
- {
- char c;
- UPCASE(ch);
- while(TRUE){
- while(from >> c, UPCASE(c), c != ch && c != '#')
- if(from.eof()) errfunc(fname); /* find ch or comment start */
- if (c == ch) break;
- /* If we made it here, a '#' comment start was found */
- while (from.get(c), c != EOL) /* 'get' doesn't skip whitespace */
- if(from.eof()) errfunc(fname); /* find end-of-line */
- }
- }
-
-
- /*
- -*++ matrix::matrix(): read from a "standard" matrix file
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix::matrix(char * initfile) /* read from "standard" matrix file */
- {
- void ch_find(istream& from, char ch, void (*errfunc)(char *), char * fname);
- void nonstandard(char *);
- filebuf f1;
- p = new matrep;
- if (f1.open(initfile,input) == 0)
- error2("cannot open matrix initializer file",initfile);
- istream from(&f1);
-
- /* Parse file initialization header */
-
- ch_find(from,'r',nonstandard,initfile); /* find the 'r'... */
- ch_find(from,'=',nonstandard, initfile); /* ...followed by an `=` */
- from >> p->m_rows; /* get row size */
- ch_find(from,'c',nonstandard, initfile); /* find the 'p'... */
- ch_find(from,'=',nonstandard, initfile); /* ...followed by an '=' */
- from >> p->m_cols; /* get column size */
- ch_find(from,':',nonstandard, initfile); /* data follows ::: */
- ch_find(from,':',nonstandard, initfile);
- ch_find(from,':',nonstandard, initfile);
-
- p->m_vec = new _Vector*[rows()];
- for (int i = 0; i < rows(); i++)
- p->m_vec[i] = new _Vector(cols());
- p->n = 1; /* we just created it: only 1 reference */
- for (int row = 0; row < rows(); row++)
- for(int col = 0; col < cols(); col++){
- from >> (*this)[row][col];
- if(from.bad()) error2("problem with matrix initializer file",initfile);
- }
- }
-
-
- /*
- -*++ nonstandard(): an error message when a "non-standard" matrix file is found
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- void nonstandard(char * fname){
- cout << fname << " is a `non-standard' file.\n";
- cout << "A `standard' matrix file must start with\n";
- cout << "the dimensions of the matrix, i.e.:\n";
- cout << "rows=12 columns=14\n";
- cout << "or abbreviated:\n";
- cout << "r=12 c=14\n";
- cout << "comments follow `#' signs to end of line\n";
- cout << "data follows :::\n";
- exit(1);
- }
-
-
- /*
- -*++ matrix::matrix(): create a special square matrix
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: create a special square matrix. If the "flag" string starts
- ** with:
- ** I: identity matrix
- ** R: square matrix with random values
- ** ++*)
- */
-
- matrix::matrix(char * flag, int dimension)
- {
- double drand48();
- int i,j;
- if (flag[0] != 'I' && flag[0] != 'R')
- error("to create identity: \"I\"; random: \"R\"");
- p = new matrep;
- p->m_vec = new _Vector*[dimension];
- p->m_rows = dimension;
- p->m_cols = dimension;
- for ( i = 0; i < dimension; i++)
- p->m_vec[i] = new _Vector(dimension);
- p->n = 1; /* so far, only one reference to this data */
-
- switch(flag[0]) {
- case 'I':
- for (i=0; i < rows(); i++)
- for ( j = 0; j < cols(); j++)
- (*this)[i][j] = (i == j ? 1 : 0);
- break;
- case 'R':
- for ( i=0; i < rows(); i++)
- for ( j = 0; j < cols(); j++)
- (*this)[i][j] = drand48();
- }
- }
-
-
- /*
- -*++ matrix::~matrix(): matrix destructor. Probably needs examining
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix::~matrix() // this is probably wrong.
- {
- if (--p->n == 0) {
- delete p->m_vec; /* delete data */
- delete p;
- }
- }
-
-
- /*
- -*++ matrix::write_standard(): write to a file in "standard" format
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: write this matrix to filename in the 'standard' format
- ** ++*)
- */
-
- void matrix::write_standard(char * filename, char * msg)
- {
- #ifndef DOS
- char *getwd(char *pathname);
- #else DOS
- char *getcwd(char *pathname);
- #endif
- char pathname[100]; /* for working directory information */
- filebuf f1;
- if (f1.open(filename,output) == 0)
- error2("cannot open or create matrix output file",filename);
- ostream to(&f1);
- to << "# " << filename << ": matrix file " << " written in `standard' format\n";
- long clock = time(0);
- to << "# " << asctime(localtime(&clock));
- #ifndef DOS
- to << "# working directory: " << getwd(pathname) << "\n";
- #else DOS
- to << "# working directory: " << getcwd(pathname) << "\n";
- #endif
- to << "# " << msg << "\n";
- to << "\nRows=" << rows() << " Columns=" << cols() << "\n";
- to << ":::\n";
- for (int row = 0; row < rows(); row++){
- for(int col = 0; col < cols(); col++){
- to << form("%6.6g ",(*this)[row][col]);
- if(to.bad()) error2("problem with matrix output file",filename);
- }
- to << "\n";
- }
- }
-
-
- /*
- -*++ matrix::operator=(): matrix "equals" using references
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator=(matrix& rval)
- {
- rval.p->n++; /* tell the rval it has another reference to it */
- if(--p->n == 0) { /* If nobody else is referencing us...*/
- delete p->m_vec; /* ...nobody else knows to make us go away...*/
- delete p;
- }
- p = rval.p; /* ...and we're pointing somewhere else (reference into rval) */
- return *this;
- }
-
-
- /*
- -*++ matrix::operator+(): add two matrices
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator+(matrix& arg)
- {
- if((rows() != arg.rows()) || (cols() != arg.cols()))
- error("matrices must be of the same dimension for addition!");
- matrix & sum= *new matrix(rows(),cols());
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- sum[i][j] = (*this)[i][j] + arg[i][j];
- return sum;
- }
-
-
- /*
- -*++ matrix::operator+(): add a double value to each element
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator+(double arg)
- {
- matrix & sum= *new matrix(rows(),cols());
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- sum[i][j] = (*this)[i][j] + arg;
- return sum;
- }
-
-
- /*
- -*++ matrix::operator*(): multiply each element by a double value
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator*(double arg)
- {
- matrix & sum= *new matrix(rows(),cols());
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- sum[i][j] = (*this)[i][j] * arg;
- return sum;
- }
-
-
- /*
- -*++ matrix::operator*(): matrix multiply
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** 9 Dec 87 Bruce Eckel Changed the test -- I had arg1.rows !=
- ** arg2.cols, which was backwards
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator*(matrix& arg)
- {
- if(cols() != arg.rows())
- error("# rows of second mat must equal # cols of first for multiply!");
- matrix & result= *new matrix(rows(),arg.cols());
- for(int row = 0; row < rows(); row++)
- for(int col = 0; col < arg.cols(); col++){
- double sum = 0;
- for(int i = 0; i < cols(); i++)
- sum += (*this)[row][i] * arg[i][col];
- result[row][col] = sum;
- };
- return result;
- }
-
-
- /*
- -*++ matrix::operator-(): subtract one matrix from another
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator-(matrix& arg)
- {
- if((rows() != arg.rows()) || (cols() != arg.cols()))
- error("matrices must be of the same dimension for subtraction!\n");
- matrix & sum= *new matrix(rows(),cols());
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- sum[i][j] = (*this)[i][j] - arg[i][j];
- return sum;
- }
-
-
- /*
- -*++ matrix::operator-(): unary minus each element in a matrix
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- matrix & matrix::operator-()
- {
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- (*this)[i][j] *= -1;
- return *this;
- }
-
-
- /*
- -*++ matrix::operator==(): test for matrix eqivalence
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- int matrix::operator==(matrix& arg)
- {
- if((rows() != arg.rows()) || (cols() != arg.cols()))
- error("matrices must be of the same dimension for equivalence test!\n");
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- if( (*this)[i][j] != arg[i][j])
- return 0;
- return ~0;
- }
-
-
- /*
- -*++ matrix::operator!=(): test for matrix eqivalence
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- int matrix::operator!=(matrix& arg)
- {
- if((rows() != arg.rows()) || (cols() != arg.cols()))
- error("matrices must be of the same dimension for inequivalence!\n");
- for (int i=0; i< rows(); i++)
- for (int j = 0; j < cols(); j++)
- if( (*this)[i][j] == arg[i][j])
- return 0;
- return ~0;
- }
-
-
- /*
- -*++ matrix::operator<<: print a matrix to standard out
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- ostream& operator<<(ostream &s, matrix& mat)
- {
- for (int i=0; i< mat.rows(); i++){
- for (int j = 0; j < mat.cols(); j++)
- s << form("%6.6g ",mat[i][j]);
- s << "\n";
- }
- return s;
- }
-
-
- /*
- -*++ matrix::operator>>():
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- istream& operator>>(istream& s, matrix& mat)
- {
- double val = 0;
- for (int row = 0; row < mat.rows(); row++)
- for(int col = 0; col < mat.cols(); col++){
- s >> val;
- if (s.bad())
- mat.error("bad matrix initialization input\n");
- if (s.eof())
- mat.error("end of matrix initialization input before matrix full\n");
- mat[row][col] = val;
- }
- return s;
- }
-
-
- /*
- -*++ matrix::file_get(): fills a matrix from a `non-standard' ASCII file
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: fills a matrix of known size from a `non-standard' file of
- ** numbers
- ** ++*)
- */
-
- void matrix::file_get(char * infile)
- {
- filebuf f1;
- if (f1.open(infile,input) == 0)
- error2("cannot open matrix initializer file",infile);
- istream from(&f1);
- for (int row = 0; row < rows(); row++)
- for(int col = 0; col < cols(); col++){
- from >> (*this)[row][col];
- if(from.bad()) error2("problem with matrix initializer file",infile);
- }
- }
-
-
- /*
- -*++ matrix::file_put(): writes a matrix to a "non-standard" ASCII file
- **
- ** (*++ history:
- ** 4 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- void matrix::file_put(char * outfile)
- {
- filebuf f1;
- if (f1.open(outfile,output) == 0)
- error2("cannot open or create matrix output file",outfile);
- ostream to(&f1);
- for (int row = 0; row < rows(); row++){
- for(int col = 0; col < cols(); col++){
- to << (*this)[row][col];
- to << " ";
- if(to.bad()) error2("problem with matrix output file",outfile);
- }
- to << "\n";
- }
- }
-
-
- /*
- -*++ operator<<(): output for XY_vec
- **
- ** (*++ history:
- ** 11 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- ostream& operator<<(ostream &s, XY_vec& v) {
- s << " X: Y:\n";
- for(int i = 0; i < v.size(); i++)
- s << form("%6.6g %6.6g\n",v.X.Indep(i),v.Y[i]);
- return s;
- }
-
-
- /*
- -*++ XY_vec::floatvect(): return a pointer to an array of floating-point #s
- **
- ** (*++ history:
- ** 14 Dec 87 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed: What is this terminated by?
- ** ++*)
- */
-
- float * XY_vec::floatvect()
- {
- float * result = new float[2 * size()];
- for (int i = 0; i < size() * 2; i += 2) {
- result[i] = (float)X.Indep(i/2);
- result[i+1] = (float)Y[i/2];
- }
- return result;
- }
-
-
- /*
- -*++ ColVec::doublvect(): returns a simple array of double numbers
- **
- ** (*++ history:
- ** 15 Jan 88 Bruce Eckel Creation date
- ** ++*)
- **
- ** (*++ detailed:
- ** ++*)
- */
-
- double * ColVec::doublvect()
- {
- double * result = new double[size()];
- for (int i = 0; i < size(); i++)
- result[i] = (*this)[i];
- return result;
- }